package com.jijs.soap;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPFaultException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.sun.org.apache.xalan.internal.xsltc.cmdline.Transform;

public class TestSoap {

	private final static String wsdlUrl = "http://localhost:8888/ms";
	private final static String ns = "http://www.infcn.com.cn/";

	public static void test1() throws SOAPException {
		try {
			// 1、创建消息工厂
			MessageFactory factory = MessageFactory.newInstance();
			// 2、根据消息工厂创建SOAPMessage
			SOAPMessage message = factory.createMessage();
			// 3、创建SOAPPart
			SOAPPart part = message.getSOAPPart();
			// 4、获取SAOPEnvelope
			SOAPEnvelope envelope = part.getEnvelope();
			// 5、可以通过SOAPEnvelope有效的获取相应的Body和Header等信息
			SOAPBody body = envelope.getBody();
			// 6、根据QName创建相应的节点（QName就是一个带有命名空间的）
			QName qname = new QName(ns, "add", "ns");
			// <ns:add xmlns="http://www.infcn.com.cn/" />
			// 如果使用以下方式进行设置，会见<>转换成&lt;和&gt;
			// body.addBodyElement(qname).setValue("<a>1</a><b>2</b>");
			SOAPBodyElement ele = body.addBodyElement(qname);
			ele.addChildElement("a").setValue("22");
			ele.addChildElement("b").setValue("11");

			message.writeTo(System.out);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	
	/**
	 * 请求的xml
	 * <?xml version="1.0" encoding="utf-8"?>
	 * <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
	 *   <SOAP-ENV:Header/>
	 *   <SOAP-ENV:Body>
	 *     <nn:add xmlns:nn="http://www.infcn.com.cn/">
	 *       <a>22</a>
	 *       <b>11</b>
	 *     </nn:add>
	 *   </SOAP-ENV:Body>
	 * </SOAP-ENV:Envelope>
	 * 
	 * 响应的xml
	 * <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
	 *   <S:Header/>
	 * 	 <S:Body>
	 * 	   <ns2:addResponse xmlns:ns2="http://www.infcn.com.cn/">
	 *       <addResult>33</addResult>
	 *     </ns2:addResponse>
	 *   </S:Body>
	 * </S:Envelope>
	 * 
	 * @throws SOAPException
	 * @throws IOException
	 */
	public static void add() throws SOAPException, IOException {
		// 1、创建服务
		URL url = new URL(wsdlUrl);
		QName qname = new QName(ns, "MyServiceImplService");
		Service service = Service.create(url, qname);

		// 2、创建Dispatch
		Dispatch<SOAPMessage> dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"), SOAPMessage.class,
				Service.Mode.MESSAGE);
		
		//3、创建SOAPMessage
		SOAPMessage msg = MessageFactory.newInstance().createMessage();
		SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
		SOAPBody body = envelope.getBody();

		//4、创建QName来指定消息中传递数据
		QName ename = new QName(ns, "add", "nn");//<nn:add xmlns="xx"/>
		SOAPBodyElement ele = body.addBodyElement(ename);
		ele.addChildElement("a").setValue("22");
		ele.addChildElement("b").setValue("11");
		
		msg.writeTo(System.out);
		System.out.println("invoking ...");
		
		//5、通过Dispatch传递消息
		SOAPMessage response = dispatch.invoke(msg);
		response.writeTo(System.out);
		System.out.println();
		
		//6、通过响应的消息转换为DOM对象
		Document doc = response.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
		NodeList nodeList = doc.getElementsByTagName("addResult");
		System.out.println(nodeList.item(0).getTextContent());
	}
	
	/**
	 * 16_soap消息传递和处理（基于Payload的方式）
	 * @throws SOAPException
	 * @throws IOException
	 * @throws JAXBException
	 * @throws TransformerFactoryConfigurationError
	 * @throws TransformerException
	 * @throws XPathExpressionException
	 */
	public static void addUser() throws SOAPException, IOException, JAXBException, TransformerFactoryConfigurationError, TransformerException, XPathExpressionException {
		// 1、创建服务
		URL url = new URL(wsdlUrl);
		QName qname = new QName(ns, "MyServiceImplService");
		Service service = Service.create(url, qname);

		// 2、创建Dispatch 通过原数据的方式传输
		Dispatch<Source> dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"), Source.class,
				Service.Mode.PAYLOAD);
		
		// 3、根据用户对象创建相应的xml
		User user = new User(3, "zs", "张三", "111111");
		JAXBContext ctx = JAXBContext.newInstance(User.class);
		Marshaller mar = ctx.createMarshaller();
		//不要xml中的头信息
		mar.setProperty(Marshaller.JAXB_FRAGMENT, true);
		StringWriter writer = new StringWriter();
		mar.marshal(user, writer);
		System.out.println(writer);
		
		//4、封装相应的part addUser;
		String payload = "<nn:addUser xmlns:nn=\""+ns+"\">"+writer.toString()+"</nn:addUser>";
		System.out.println(payload);
		StreamSource rs = new StreamSource(new StringReader(payload));
		
		//5、通过dispatch传递payload
		Source response = dispatch.invoke(rs);
		
		//6、将Source转换成DOM进行操作，使用Transform对象转换
		Transformer tran = TransformerFactory.newInstance().newTransformer();
		DOMResult result = new DOMResult();
		tran.transform(response, result);
		
		//7、处理相应信息(通过Xpath处理)
		XPath xpath = XPathFactory.newInstance().newXPath();
		NodeList n1 = (NodeList)xpath.evaluate("//user", result.getNode(), XPathConstants.NODESET);
		System.out.println(n1.item(0).getNodeName());
		
		
		//8、使用jaxb反编排
		User ru = (User)ctx.createUnmarshaller().unmarshal(n1.item(0));
		System.out.println(ru.getNickName());
	}
	
	public static void list() throws SOAPException, IOException, JAXBException {
		// 1、创建服务
		URL url = new URL(wsdlUrl);
		QName qname = new QName(ns, "MyServiceImplService");
		Service service = Service.create(url, qname);

		// 2、创建Dispatch
		Dispatch<SOAPMessage> dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"), SOAPMessage.class,
				Service.Mode.MESSAGE);
		
		//3、创建SOAPMessage
		SOAPMessage msg = MessageFactory.newInstance().createMessage();
		SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
		SOAPBody body = envelope.getBody();

		//4、创建QName来指定消息中传递数据
		QName ename = new QName(ns, "list", "nn");//<nn:add xmlns="xx"/>
		body.addBodyElement(ename);
		
		msg.writeTo(System.out);
		System.out.println("invoking ...");
		
		//5、通过Dispatch传递消息
		SOAPMessage response = dispatch.invoke(msg);
		response.writeTo(System.out);
		System.out.println();
		
		//6、通过响应的消息转换为DOM对象
		Document doc = response.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
		NodeList nodeList = doc.getElementsByTagName("user");
		
		System.out.println();
		JAXBContext ctx = JAXBContext.newInstance(User.class);
		for (int i=0; i<nodeList.getLength(); i++) {
			Node n = nodeList.item(i);
			User u = (User)ctx.createUnmarshaller().unmarshal(n);
			System.out.println(u.getNickName());
		}
	}
	
	/**
	 * 17_SOAP显示的创建和处理SOAPHeader的信息
	 * 请求soap信息
	 * <?xml version="1.0" encoding="utf-8"?>
	 * <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
	 *   <SOAP-ENV:Header>
	 *     <nn:authInfo xmlns:nn="http://www.infcn.com.cn/"></nn:authInfo>
	 *   </SOAP-ENV:Header>
	 *   <SOAP-ENV:Body>
	 *     <nn:listHeader xmlns:nn="http://www.infcn.com.cn/"></nn:listHeader>
	 *   </SOAP-ENV:Body>
	 *  </SOAP-ENV:Envelope>

	 * @throws SOAPException
	 * @throws IOException
	 * @throws JAXBException
	 */
	public static void listHeader() throws SOAPException, IOException, JAXBException {
		// 1、创建服务
		URL url = new URL(wsdlUrl);
		QName qname = new QName(ns, "MyServiceImplService");
		Service service = Service.create(url, qname);

		// 2、创建Dispatch
		Dispatch<SOAPMessage> dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"), SOAPMessage.class,
				Service.Mode.MESSAGE);
		
		//3、创建SOAPMessage
		SOAPMessage msg = MessageFactory.newInstance().createMessage();
		SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
		SOAPBody body = envelope.getBody();
		
		//3.2 处理header信息
		SOAPHeader header = envelope.getHeader();
		if(header==null){ 
			envelope.addHeader();
		}
		QName hname = new QName(ns, "authInfo", "nn");
		header.addHeaderElement(hname).setValue("aabbccdd");;

		//4、创建QName来指定消息中传递数据
		QName ename = new QName(ns, "listHeader", "nn");//<nn:add xmlns="xx"/>
		body.addBodyElement(ename);
		
		msg.writeTo(System.out);
		System.out.println("invoking ...");
		
		//5、通过Dispatch传递消息
		SOAPMessage response = dispatch.invoke(msg);
		response.writeTo(System.out);
		System.out.println();
		
		//6、通过响应的消息转换为DOM对象
		Document doc = response.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
		NodeList nodeList = doc.getElementsByTagName("user");
		
		System.out.println();
		JAXBContext ctx = JAXBContext.newInstance(User.class);
		for (int i=0; i<nodeList.getLength(); i++) {
			Node n = nodeList.item(i);
			User u = (User)ctx.createUnmarshaller().unmarshal(n);
			System.out.println(u.getNickName());
		}
	}
	
	/**
	 * 异常处理
	 * @throws SOAPException
	 * @throws IOException
	 * @throws JAXBException
	 */
	public static void login() throws SOAPException, IOException, JAXBException {
		// 1、创建服务
		URL url = new URL(wsdlUrl);
		QName qname = new QName(ns, "MyServiceImplService");
		Service service = Service.create(url, qname);

		// 2、创建Dispatch
		Dispatch<SOAPMessage> dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"), SOAPMessage.class,
				Service.Mode.MESSAGE);
		
		//3、创建SOAPMessage
		SOAPMessage msg = MessageFactory.newInstance().createMessage();
		SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
		SOAPBody body = envelope.getBody();
		
		//4、创建QName来指定消息中传递数据
		QName ename = new QName(ns, "login", "nn");//<nn:add xmlns="xx"/>
		SOAPBodyElement ele = body.addBodyElement(ename);
		ele.addChildElement("userName").setValue("admin1");
		ele.addChildElement("password").setValue("123456");
		
		msg.writeTo(System.out);
		System.out.println("invoking ...");
		
		try{
			//5、通过Dispatch传递消息
			SOAPMessage response = dispatch.invoke(msg);
			response.writeTo(System.out);
			System.out.println();
			
			//6、通过响应的消息转换为DOM对象
			Document doc = response.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
			NodeList nodeList = doc.getElementsByTagName("user");
			
			System.out.println();
			JAXBContext ctx = JAXBContext.newInstance(User.class);
			for (int i=0; i<nodeList.getLength(); i++) {
				Node n = nodeList.item(i);
				User u = (User)ctx.createUnmarshaller().unmarshal(n);
				System.out.println(u.getNickName());
			}
		}catch(SOAPFaultException e){
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception {
//		 test1();
//		 add();
//		 addUser();
//		 list();
//		 listHeader();
		 login();
	}
}
